<!DOCTYPE html>
<html>
<head>
    

    
<!-- Tencent Speed -->
<script>var _speedMark = new Date()</script>
<!-- End Tencent Speed -->
<!-- Tencent Analysis -->
<script async src="//tajs.qq.com/stats?sId=61422473"></script>
<!-- End Tencent Analysis -->


    



    <meta charset="utf-8">
    
    
    
    <title>即时通讯框架T-io之WebSocket协议再之HelloWorld | z77z的小码窝 | 年少无为，卖码为生。</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    
    <meta name="theme-color" content="#ffff00">
    
    
    <meta name="keywords" content="websocket">
    <meta name="description" content="一.t-io是干嘛的
这个框架已经开源到码云上面，介绍比较详细，链接：https://git.oschina.net/tywo45/t-io，由于官方介绍中的入门程序客户端和服务端都是用的java写的，而且是用简单的自定义TCP协议进行通信的，也有一个websocket协议的列子，感觉有点复杂，不好入门。就想着使用javascript来做客户端，t-io做服务端，采用websocket协议搞一个h">
<meta property="og:type" content="article">
<meta property="og:title" content="即时通讯框架T-io之WebSocket协议再之HelloWorld">
<meta property="og:url" content="http://z77z.oschina.io/2017/06/05/即时通讯框架T-io之WebSocket协议再之HelloWorld/index.html">
<meta property="og:site_name" content="z77z的小码窝">
<meta property="og:description" content="一.t-io是干嘛的
这个框架已经开源到码云上面，介绍比较详细，链接：https://git.oschina.net/tywo45/t-io，由于官方介绍中的入门程序客户端和服务端都是用的java写的，而且是用简单的自定义TCP协议进行通信的，也有一个websocket协议的列子，感觉有点复杂，不好入门。就想着使用javascript来做客户端，t-io做服务端，采用websocket协议搞一个h">
<meta property="og:updated_time" content="2017-06-07T13:42:41.348Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="即时通讯框架T-io之WebSocket协议再之HelloWorld">
<meta name="twitter:description" content="一.t-io是干嘛的
这个框架已经开源到码云上面，介绍比较详细，链接：https://git.oschina.net/tywo45/t-io，由于官方介绍中的入门程序客户端和服务端都是用的java写的，而且是用简单的自定义TCP协议进行通信的，也有一个websocket协议的列子，感觉有点复杂，不好入门。就想着使用javascript来做客户端，t-io做服务端，采用websocket协议搞一个h">
    
        <link rel="alternate" type="application/atom+xml" title="z77z的小码窝" href="/atom.xml">
    
    <link rel="shortcut icon" href="/favicon.ico">
    <link rel="stylesheet" href="/css/style.css?v=1.4.3">
    <script>window.lazyScripts=[]</script>
</head>

<body>
    <div id="loading" class="active"></div>

    <aside id="menu" class="hide" >
  <div class="inner flex-row-vertical">
    <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="menu-off">
        <i class="icon icon-lg icon-close"></i>
    </a>
    <div class="brand-wrap" style="background-image:url(/img/brand.jpg)">
      <div class="brand">
        <a href="/" class="avatar waves-effect waves-circle waves-light">
          <img src="/img/avatar.jpg">
        </a>
        <hgroup class="introduce">
          <h5 class="nickname">邹海清</h5>
          <a href="mailto:1093615728@qq.com" title="1093615728@qq.com" class="mail">1093615728@qq.com</a>
        </hgroup>
      </div>
    </div>
    <div class="scroll-wrap flex-col">
      <ul class="nav">
        
            <li class="waves-block waves-effect">
              <a href="/"  >
                <i class="icon icon-lg icon-home"></i>
                主页
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="/archives"  >
                <i class="icon icon-lg icon-archives"></i>
                归档
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="/tags"  >
                <i class="icon icon-lg icon-tags"></i>
                标签
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="https://git.oschina.net/z77z" target="_blank" >
                <i class="icon icon-lg icon-git"></i>
                git
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="http://t.qq.com/zouhaiqing123" target="_blank" >
                <i class="icon icon-lg icon-weibo"></i>
                微博
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="/custom"  >
                <i class="icon icon-lg icon-link"></i>
                404页面测试
              </a>
            </li>
        
      </ul>
    </div>
  </div>
</aside>

    <main id="main">
        <header class="top-header" id="header">
    <div class="flex-row">
        <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light on" id="menu-toggle">
          <i class="icon icon-lg icon-navicon"></i>
        </a>
        <div class="flex-col header-title ellipsis">即时通讯框架T-io之WebSocket协议再之HelloWorld</div>
        
        <div class="search-wrap" id="search-wrap">
            <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="back">
                <i class="icon icon-lg icon-chevron-left"></i>
            </a>
            <input type="text" id="key" class="search-input" autocomplete="off" placeholder="输入感兴趣的关键字">
            <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="search">
                <i class="icon icon-lg icon-search"></i>
            </a>
        </div>
        
        
        <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="menuShare">
            <i class="icon icon-lg icon-share-alt"></i>
        </a>
        
    </div>
</header>
<header class="content-header post-header">

    <div class="container fade-scale">
        <h1 class="title">即时通讯框架T-io之WebSocket协议再之HelloWorld</h1>
        <h5 class="subtitle">
            
                <time datetime="2017-06-05T15:14:44.000Z" itemprop="datePublished" class="page-time">
  2017-06-05
</time>


            
        </h5>
    </div>

    


</header>


<div class="container body-wrap">
    
    <aside class="post-widget">
        <nav class="post-toc-wrap" id="post-toc">
            <h4>TOC</h4>
            <ol class="post-toc"><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#一-t-io是干嘛的"><span class="post-toc-number">1.</span> <span class="post-toc-text">一.t-io是干嘛的</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#二-WebSocket协议咋回事"><span class="post-toc-number">2.</span> <span class="post-toc-text">二.WebSocket协议咋回事</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#三-T-io服务端编写"><span class="post-toc-number">3.</span> <span class="post-toc-text">三.T-io服务端编写</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#四-javascript客户端编写"><span class="post-toc-number">4.</span> <span class="post-toc-text">四.javascript客户端编写</span></a></li></ol>
        </nav>
    </aside>
    
<article id="post-即时通讯框架T-io之WebSocket协议再之HelloWorld"
  class="post-article article-type-post fade" itemprop="blogPost">

    <div class="post-card">
        <h1 class="post-card-title">即时通讯框架T-io之WebSocket协议再之HelloWorld</h1>
        <div class="post-meta">
            <time class="post-time" title="2017-06-05 23:14:44" datetime="2017-06-05T15:14:44.000Z"  itemprop="datePublished">2017-06-05</time>

            


            
<span id="busuanzi_container_page_pv" title="文章总阅读量" style='display:none'>
    <i class="icon icon-eye icon-pr"></i><span id="busuanzi_value_page_pv"></span>
</span>


            

        </div>
        <div class="post-content" id="post-content" itemprop="postContent">
            <h2 id="一-t-io是干嘛的"><a href="#一-t-io是干嘛的" class="headerlink" title="一.t-io是干嘛的"></a>一.t-io是干嘛的</h2><hr>
<p>这个框架已经开源到码云上面，介绍比较详细，链接：<a href="https://git.oschina.net/tywo45/t-io" target="_blank" rel="external">https://git.oschina.net/tywo45/t-io</a>，由于官方介绍中的入门程序客户端和服务端都是用的java写的，而且是用简单的自定义TCP协议进行通信的，也有一个websocket协议的列子，感觉有点复杂，不好入门。就想着使用javascript来做客户端，t-io做服务端，采用websocket协议搞一个helloworld。</p>
<h2 id="二-WebSocket协议咋回事"><a href="#二-WebSocket协议咋回事" class="headerlink" title="二.WebSocket协议咋回事"></a>二.WebSocket协议咋回事</h2><hr>
<p>首先，t-io框架简单说就是封装一下些个：</p>
<ul>
<li>内置心跳检测</li>
<li>内置心跳发送</li>
<li>各种便捷的绑定API</li>
<li>各种便捷的发送API</li>
<li>一行代码拥有自动重连功能</li>
<li>各项消息统计等功能，全部一键内置搞定，省却各种烦恼</li>
</ul>
<p>所以我们收到客户端发来的websocket协议的包，在服务端就要做对应的解包，那我们还要了解websocket包的结构和通信建立的过程：</p>
<p>①握手阶段：</p>
<p>客户端和服务器建立TCP连接之后，客户端发送握手请求，随后服务器发送握手响应即完成握手阶段。如下：</p>
<p>客户端握手请求类似如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">GET /chat HTTP/1.1</div><div class="line">Host: server.example.com</div><div class="line">Upgrade: websocket</div><div class="line">Connection: Upgrade</div><div class="line">Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==</div><div class="line">Sec-WebSocket-Protocol: chat, superchat</div><div class="line">Sec-WebSocket-Version: 13</div><div class="line">Origin: http://example.com</div></pre></td></tr></table></figure></p>
<p>服务器的握手响应类似如下：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">HTTP/1.1 101 Switching Protocols</div><div class="line">Upgrade: websocket</div><div class="line">Connection: Upgrade</div><div class="line">Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=</div><div class="line">Sec-WebSocket-Protocol: chat</div></pre></td></tr></table></figure>
<p>②握手成功后开始发送数据帧</p>
<p>这是Websocket的数据传输协议，聊天信息一般会按照这个协议的规则来传输，下图中的一整个东西称为一个数据帧，数据帧的成帧和解析是处理这个协议时最麻烦的一部分了。具体这个表怎么看可以参照</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div></pre></td><td class="code"><pre><div class="line">0                   1                   2                   3</div><div class="line">  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1</div><div class="line"> +-+-+-+-+-------+-+-------------+-------------------------------+</div><div class="line"> |F|R|R|R| opcode|M| Payload len |    Extended payload length    |</div><div class="line"> |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |</div><div class="line"> |N|V|V|V|       |S|             |   (if payload len==126/127)   |</div><div class="line"> | |1|2|3|       |K|             |                               |</div><div class="line"> +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +</div><div class="line"> |     Extended payload length continued, if payload len == 127  |</div><div class="line"> + - - - - - - - - - - - - - - - +-------------------------------+</div><div class="line"> |                               |Masking-key, if MASK set to 1  |</div><div class="line"> +-------------------------------+-------------------------------+</div><div class="line"> | Masking-key (continued)       |          Payload Data         |</div><div class="line"> +-------------------------------- - - - - - - - - - - - - - - - +</div><div class="line"> :                     Payload Data continued ...                :</div><div class="line"> + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +</div><div class="line"> |                     Payload Data continued ...                |</div><div class="line"> +---------------------------------------------------------------+</div><div class="line"></div><div class="line"> 具体每一bit的意思</div><div class="line">FIN      1bit 表示信息的最后一帧</div><div class="line">RSV 1-3  1bit each 以后备用的 默认都为 0</div><div class="line">Opcode   4bit 帧类型，稍后细说</div><div class="line">Mask     1bit 掩码，是否加密数据，默认必须置为1 （这里很蛋疼）</div><div class="line">Payload  7bit 数据的长度</div><div class="line">Masking-key      1 or 4 bit 掩码</div><div class="line">Payload data     (x + y) bytes 数据</div><div class="line">Extension data   x bytes  扩展数据</div><div class="line">Application data y bytes  程序数据</div></pre></td></tr></table></figure>
<h2 id="三-T-io服务端编写"><a href="#三-T-io服务端编写" class="headerlink" title="三.T-io服务端编写"></a>三.T-io服务端编写</h2><hr>
<p>整体的编写和框架自带的Helloworld程序模式一致，需要改变的就是encode()编码方法和decode()解码方法，因为需要根据websocket协议来。</p>
<p><strong>收到消息后先解码，再判断包的类型，交给响应类型的handler。发送消息先编码。</strong></p>
<p><strong>①握手</strong></p>
<p>decode()解码方法：</p>
<p>由于客户端收到的第一个包是握手包，所以：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> (!barrageSessionContext.isHandshaked()) <span class="comment">// 如果还没有握手，则先进行握手操作</span></div><div class="line">&#123;</div><div class="line">	<span class="keyword">if</span> (BarragePacket.HANDSHAKE_BYTE == firstbyte) &#123;</div><div class="line">		buffer.position(<span class="number">1</span> + initPosition);</div><div class="line">		<span class="keyword">return</span> handshakePacket;</div><div class="line">	&#125; <span class="keyword">else</span> &#123;</div><div class="line">		HttpRequestPacket httpRequestPacket = HttpRequestDecoder.decode(buffer);</div><div class="line">		<span class="keyword">if</span> (httpRequestPacket == <span class="keyword">null</span>) &#123;</div><div class="line">			<span class="keyword">return</span> <span class="keyword">null</span>;</div><div class="line">		&#125;</div><div class="line">		<span class="comment">//交给握手包的Handler</span></div><div class="line">		httpRequestPacket.setType(Type.COMMAND_HANDSHAKE_REQ);</div><div class="line">		barrageSessionContext.setWebsocket(<span class="keyword">true</span>);</div><div class="line">		<span class="keyword">return</span> httpRequestPacket;</div><div class="line">	&#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="comment">//握手成功后在barrageSessionContext中保存此次连接的握手情况.</span></div><div class="line"><span class="keyword">boolean</span> isWebsocket = barrageSessionContext.isWebsocket();</div></pre></td></tr></table></figure>
<p>握手包的Handler，返回握手响应包，让客户端知道握手成功，可以进行数据传输了，：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HandshakeReqHandler</span> <span class="keyword">implements</span> <span class="title">BarrageHandlerIntf</span>&lt;<span class="title">HandshakeBody</span>&gt; </span>&#123;</div><div class="line"></div><div class="line">	<span class="keyword">private</span> BarragePacket handshakeRespPacket = <span class="keyword">new</span> BarragePacket(Type.COMMAND_HANDSHAKE_RESP);</div><div class="line">	</div><div class="line">	<span class="meta">@Override</span></div><div class="line">	<span class="function"><span class="keyword">public</span> Object <span class="title">handler</span><span class="params">(</span></span></div><div class="line">			BarragePacket packet,</div><div class="line">			String body,</div><div class="line">			ChannelContext&lt;BarrageSessionContext, BarragePacket, Object&gt; channelContext)</div><div class="line">			<span class="keyword">throws</span> Exception &#123;</div><div class="line">		BarrageSessionContext barrageSessionContext = channelContext.getSessionContext();</div><div class="line">		barrageSessionContext.setHandshaked(<span class="keyword">true</span>);</div><div class="line"></div><div class="line">		<span class="keyword">boolean</span> isWebsocket = barrageSessionContext.isWebsocket();</div><div class="line">		<span class="keyword">if</span> (isWebsocket)</div><div class="line">		&#123;</div><div class="line">			HttpRequestPacket httpRequestPacket = (HttpRequestPacket) packet;</div><div class="line">			HttpResponsePacket httpResponsePacket = updateWebSocketProtocol(httpRequestPacket);</div><div class="line">			<span class="keyword">if</span> (httpResponsePacket != <span class="keyword">null</span>)</div><div class="line">			&#123;</div><div class="line">				<span class="comment">//发送握手响应包，交给握手响应的handler</span></div><div class="line">				httpResponsePacket.setType(Type.COMMAND_HANDSHAKE_RESP);</div><div class="line">				Aio.send(channelContext, httpResponsePacket);</div><div class="line">			&#125; <span class="keyword">else</span></div><div class="line">			&#123;</div><div class="line">				Aio.remove(channelContext, <span class="string">"不是websocket协议"</span>);</div><div class="line">			&#125;</div><div class="line">		&#125; <span class="keyword">else</span></div><div class="line">		&#123;</div><div class="line">			Aio.send(channelContext, handshakeRespPacket);</div><div class="line">		&#125;</div><div class="line">		<span class="keyword">return</span> <span class="keyword">null</span>;</div><div class="line">	&#125;</div><div class="line">	</div><div class="line">	<span class="function"><span class="keyword">public</span> HttpResponsePacket <span class="title">updateWebSocketProtocol</span><span class="params">(HttpRequestPacket httpRequestPacket)</span></span></div><div class="line">	&#123;</div><div class="line">		Map&lt;String, String&gt; headers = httpRequestPacket.getHeaders();</div><div class="line"></div><div class="line">		String Sec_WebSocket_Key = headers.get(<span class="string">"Sec-WebSocket-Key"</span>);</div><div class="line"></div><div class="line">		<span class="keyword">if</span> (StringUtils.isNotBlank(Sec_WebSocket_Key))</div><div class="line">		&#123;</div><div class="line">			String Sec_WebSocket_Key_Magic = Sec_WebSocket_Key + <span class="string">"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"</span>;</div><div class="line">			<span class="keyword">byte</span>[] key_array = SHA1Util.SHA1(Sec_WebSocket_Key_Magic);</div><div class="line">			String acceptKey = BASE64Util.byteArrayToBase64(key_array);</div><div class="line">			HttpResponsePacket httpResponsePacket = <span class="keyword">new</span> HttpResponsePacket();</div><div class="line"></div><div class="line">			HttpResponseStatus httpResponseStatus = HttpResponseStatus.C101;</div><div class="line">			httpResponsePacket.setHttpResponseStatus(httpResponseStatus);</div><div class="line"></div><div class="line">			Map&lt;String, String&gt; respHeaders = <span class="keyword">new</span> HashMap&lt;&gt;();</div><div class="line">			respHeaders.put(<span class="string">"Connection"</span>, <span class="string">"Upgrade"</span>);</div><div class="line">			respHeaders.put(<span class="string">"Upgrade"</span>, <span class="string">"WebSocket"</span>);</div><div class="line">			respHeaders.put(<span class="string">"Sec-WebSocket-Accept"</span>, acceptKey);</div><div class="line">			httpResponsePacket.setHeaders(respHeaders);</div><div class="line">			<span class="keyword">return</span> httpResponsePacket;</div><div class="line">		&#125;</div><div class="line">		<span class="keyword">return</span> <span class="keyword">null</span>;</div><div class="line">	&#125;</div><div class="line"></div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>encode()编码方法:</p>
<p>上面在握手包的handler中，调用了send方法，发送了一个握手响应包，所以要在编码的时候先判断是否是握手响应包，对其编码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> (packet.getType() == Type.COMMAND_HANDSHAKE_RESP) &#123;</div><div class="line">	<span class="keyword">if</span> (isWebsocket) &#123;</div><div class="line">		<span class="keyword">return</span> HttpResponseEncoder.encode((HttpResponsePacket) packet, groupContext, channelContext);</div><div class="line">	&#125; <span class="keyword">else</span> &#123;</div><div class="line">		ByteBuffer buffer = ByteBuffer.allocate(<span class="number">1</span>);</div><div class="line">		buffer.put(BarragePacket.HANDSHAKE_BYTE);</div><div class="line">		<span class="keyword">return</span> buffer;</div><div class="line">	&#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>握手响应包的编码<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> ByteBuffer <span class="title">encode</span><span class="params">(HttpResponsePacket httpResponsePacket, GroupContext&lt;BarrageSessionContext, BarragePacket, Object&gt; groupContext, ChannelContext&lt;BarrageSessionContext, BarragePacket, Object&gt; channelContext)</span></span></div><div class="line">	&#123;</div><div class="line">		<span class="keyword">int</span> bodyLength = <span class="number">0</span>;</div><div class="line">		<span class="keyword">byte</span>[] httpResponseBody = httpResponsePacket.getHttpResponseBody();</div><div class="line">		<span class="keyword">if</span> (httpResponseBody != <span class="keyword">null</span>)</div><div class="line">		&#123;</div><div class="line">			bodyLength = httpResponseBody.length;</div><div class="line">		&#125;</div><div class="line"></div><div class="line">		StringBuilder sb = <span class="keyword">new</span> StringBuilder(<span class="number">128</span>);</div><div class="line"></div><div class="line">		HttpResponseStatus httpResponseStatus = httpResponsePacket.getHttpResponseStatus();</div><div class="line">		<span class="comment">//		httpResponseStatus.get</span></div><div class="line">		sb.append(<span class="string">"HTTP/1.1 "</span>).append(httpResponseStatus.getStatus()).append(<span class="string">" "</span>).append(httpResponseStatus.getDescription()).append(<span class="string">"\r\n"</span>);</div><div class="line"></div><div class="line">		Map&lt;String, String&gt; headers = httpResponsePacket.getHeaders();</div><div class="line">		<span class="keyword">if</span> (headers != <span class="keyword">null</span> &amp;&amp; headers.size() &gt; <span class="number">0</span>)</div><div class="line">		&#123;</div><div class="line">			headers.put(<span class="string">"Content-Length"</span>, bodyLength + <span class="string">""</span>);</div><div class="line">			Set&lt;Entry&lt;String, String&gt;&gt; set = headers.entrySet();</div><div class="line">			<span class="keyword">for</span> (Entry&lt;String, String&gt; entry : set)</div><div class="line">			&#123;</div><div class="line">				sb.append(entry.getKey()).append(<span class="string">": "</span>).append(entry.getValue()).append(<span class="string">"\r\n"</span>);</div><div class="line">			&#125;</div><div class="line">		&#125;</div><div class="line">		sb.append(<span class="string">"\r\n"</span>);</div><div class="line"></div><div class="line">		<span class="keyword">byte</span>[] headerBytes = <span class="keyword">null</span>;</div><div class="line">		<span class="keyword">try</span></div><div class="line">		&#123;</div><div class="line">			headerBytes = sb.toString().getBytes(<span class="string">"utf-8"</span>);</div><div class="line">		&#125; <span class="keyword">catch</span> (Exception e)</div><div class="line">		&#123;</div><div class="line">			<span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(e);</div><div class="line">		&#125;</div><div class="line"></div><div class="line">		ByteBuffer buffer = ByteBuffer.allocate(headerBytes.length + bodyLength);</div><div class="line">		buffer.put(headerBytes);</div><div class="line"></div><div class="line">		<span class="keyword">if</span> (bodyLength &gt; <span class="number">0</span>)</div><div class="line">		&#123;</div><div class="line">			buffer.put(httpResponseBody);</div><div class="line">		&#125;</div><div class="line">		<span class="keyword">return</span> buffer;</div><div class="line">	&#125;</div></pre></td></tr></table></figure></p>
<p><strong>②数据包</strong></p>
<p>decode()解码方法：</p>
<p>上面握手成功的时候会在BarrageSessionContext中保存握手的情况。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> (isWebsocket) <span class="comment">// 走的websocket协议</span></div><div class="line">&#123;</div><div class="line">	WebsocketPacket websocketPacket = WebsocketDecoder.decode(buffer, channelContext);</div><div class="line">	<span class="keyword">if</span> (websocketPacket == <span class="keyword">null</span>) &#123;</div><div class="line">		<span class="keyword">return</span> <span class="keyword">null</span>;</div><div class="line">	&#125;</div><div class="line">	Opcode opcode = websocketPacket.getWsOpcode();</div><div class="line">	<span class="keyword">if</span> (opcode == Opcode.BINARY) &#123;</div><div class="line">		<span class="keyword">byte</span>[] wsBody = websocketPacket.getWsBody();</div><div class="line">		<span class="keyword">if</span> (wsBody == <span class="keyword">null</span> || wsBody.length == <span class="number">0</span>) &#123;</div><div class="line">			<span class="keyword">throw</span> <span class="keyword">new</span> AioDecodeException(<span class="string">"错误的websocket包，body为空"</span>);</div><div class="line">		&#125;</div><div class="line"></div><div class="line">		BarragePacket barragePacket = <span class="keyword">new</span> BarragePacket(Type.COMMAND_HANDSHAKE_RESP);</div><div class="line"></div><div class="line">		<span class="keyword">if</span> (wsBody.length &gt; <span class="number">1</span>) &#123;</div><div class="line">			<span class="keyword">byte</span>[] dst = <span class="keyword">new</span> <span class="keyword">byte</span>[wsBody.length - <span class="number">1</span>];</div><div class="line">			System.arraycopy(wsBody, <span class="number">1</span>, dst, <span class="number">0</span>, dst.length);</div><div class="line">			barragePacket.setBody(dst);</div><div class="line">		&#125;</div><div class="line">		<span class="keyword">return</span> barragePacket;</div><div class="line">	&#125; <span class="keyword">else</span> <span class="keyword">if</span> (opcode == Opcode.PING || opcode == Opcode.PONG) &#123;</div><div class="line">		<span class="keyword">return</span> heartbeatPacket;</div><div class="line">	&#125; <span class="keyword">else</span> <span class="keyword">if</span> (opcode == Opcode.CLOSE) &#123;</div><div class="line">		BarragePacket barragePacket = <span class="keyword">new</span> BarragePacket(Type.COMMAND_CLOSE_REQ);</div><div class="line">		<span class="keyword">return</span> barragePacket;</div><div class="line">	&#125; <span class="keyword">else</span> <span class="keyword">if</span> (opcode == Opcode.TEXT) &#123;</div><div class="line">		<span class="keyword">byte</span>[] wsBody = websocketPacket.getWsBody();</div><div class="line">		<span class="keyword">if</span> (wsBody == <span class="keyword">null</span> || wsBody.length == <span class="number">0</span>) &#123;</div><div class="line">			<span class="keyword">throw</span> <span class="keyword">new</span> AioDecodeException(<span class="string">"错误的websocket包，body为空"</span>);</div><div class="line">		&#125;</div><div class="line">		BarragePacket barragePacket = <span class="keyword">new</span> BarragePacket(Type.P2P_REQ);</div><div class="line">		<span class="keyword">if</span> (wsBody.length &gt; <span class="number">1</span>) &#123;</div><div class="line">			barragePacket.setBody(wsBody);</div><div class="line">		&#125;</div><div class="line">		<span class="keyword">return</span> barragePacket;</div><div class="line">	&#125; <span class="keyword">else</span> &#123;</div><div class="line">		<span class="keyword">throw</span> <span class="keyword">new</span> AioDecodeException(<span class="string">"错误的websocket包，错误的Opcode"</span>);</div><div class="line">	&#125;</div><div class="line"></div><div class="line">&#125; <span class="keyword">else</span> &#123;</div><div class="line">	<span class="keyword">if</span> (BarragePacket.HEARTBEAT_BYTE == firstbyte) &#123;</div><div class="line">		buffer.position(<span class="number">1</span> + initPosition);</div><div class="line">		<span class="keyword">return</span> heartbeatPacket;</div><div class="line">	&#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>数据包的handler：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">P2PReqHandler</span> <span class="keyword">implements</span> <span class="title">BarrageHandlerIntf</span>&lt;<span class="title">P2PReqBody</span>&gt;</span>&#123;</div><div class="line"></div><div class="line">	<span class="meta">@Override</span></div><div class="line">	<span class="function"><span class="keyword">public</span> Object <span class="title">handler</span><span class="params">(</span></span></div><div class="line">			BarragePacket packet,</div><div class="line">			String jsonStr,</div><div class="line">			ChannelContext&lt;BarrageSessionContext, BarragePacket, Object&gt; channelContext)</div><div class="line">			<span class="keyword">throws</span> Exception &#123;</div><div class="line">		System.out.println(jsonStr);</div><div class="line">		BarragePacket barragePacket = <span class="keyword">new</span> BarragePacket(Type.P2P_REQ);</div><div class="line">		barragePacket.setBody((<span class="string">"收到了你的消息，你的消息是:"</span> + jsonStr).getBytes(BarragePacket.CHARSET));</div><div class="line">		Aio.send(channelContext, barragePacket);</div><div class="line">		<span class="keyword">return</span> <span class="keyword">null</span>;</div><div class="line">	&#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>这个收到消息后的处理是，发送收到的消息到客户端。</p>
<p>encode()编码方法:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">如果不是握手响应包，走websocket包的编码</div><div class="line"><span class="keyword">if</span> (isWebsocket) &#123;</div><div class="line">	<span class="keyword">return</span> WebsocketEncoder.encode(packet, groupContext, channelContext);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div></pre></td><td class="code"><pre><div class="line">public static ByteBuffer encode(BarragePacket barragePacket, GroupContext&lt;BarrageSessionContext, BarragePacket, Object&gt; groupContext,</div><div class="line">			ChannelContext&lt;BarrageSessionContext, BarragePacket, Object&gt; channelContext)</div><div class="line">&#123;</div><div class="line">	byte[] websocketHeader;</div><div class="line">	byte[] imBody = barragePacket.getBody();</div><div class="line">	int wsBodyLength = 1; //固定有一个命令码，占一位</div><div class="line">	if (imBody != null)</div><div class="line">	&#123;</div><div class="line">		wsBodyLength += imBody.length;</div><div class="line">	&#125;</div><div class="line"></div><div class="line">	byte header0 = (byte) (0x8f &amp; (Opcode.BINARY.getCode() | 0xf0));</div><div class="line"></div><div class="line">	if (wsBodyLength &lt; 126)</div><div class="line">	&#123;</div><div class="line">		websocketHeader = new byte[2];</div><div class="line">		websocketHeader[0] = header0;</div><div class="line">		websocketHeader[1] = (byte) wsBodyLength;</div><div class="line">	&#125; else if (wsBodyLength &lt; ((1 &lt;&lt; 16) - 1))</div><div class="line">	&#123;</div><div class="line">		websocketHeader = new byte[4];</div><div class="line">		websocketHeader[0] = header0;</div><div class="line">		websocketHeader[1] = 126;</div><div class="line">		websocketHeader[3] = (byte) (wsBodyLength &amp; 0xff);</div><div class="line">		websocketHeader[2] = (byte) ((wsBodyLength &gt;&gt; 8) &amp; 0x80);</div><div class="line">	&#125; else</div><div class="line">	&#123;</div><div class="line">		websocketHeader = new byte[6];</div><div class="line">		websocketHeader[0] = header0;</div><div class="line">		websocketHeader[1] = 127;</div><div class="line">		int2Byte(websocketHeader, wsBodyLength, 2);</div><div class="line">	&#125;</div><div class="line">	ByteBuffer buf = ByteBuffer.allocate(websocketHeader.length + wsBodyLength);</div><div class="line">	buf.put(websocketHeader);</div><div class="line"></div><div class="line">	buf.put(barragePacket.getType());</div><div class="line"></div><div class="line">	if (imBody != null)</div><div class="line">	&#123;</div><div class="line">		buf.put(imBody);</div><div class="line">	&#125;</div><div class="line"></div><div class="line">	return buf;</div><div class="line">&#125;</div><div class="line"></div><div class="line">public static void int2Byte(byte[] bytes, int value, int offset)</div><div class="line">&#123;</div><div class="line">	checkLength(bytes, 4, offset);</div><div class="line"></div><div class="line">	bytes[offset + 3] = (byte) ((value &amp; 0xff));</div><div class="line">	bytes[offset + 2] = (byte) ((value &gt;&gt; 8 * 1) &amp; 0xff);</div><div class="line">	bytes[offset + 1] = (byte) ((value &gt;&gt; 8 * 2) &amp; 0xff);</div><div class="line">	bytes[offset + 0] = (byte) ((value &gt;&gt; 8 * 3));</div><div class="line">&#125;</div><div class="line"></div><div class="line">private static void checkLength(byte[] bytes, int length, int offset)</div><div class="line">&#123;</div><div class="line">	if (bytes == null)</div><div class="line">	&#123;</div><div class="line">		throw new IllegalArgumentException(&quot;null&quot;);</div><div class="line">	&#125;</div><div class="line"></div><div class="line">	if (offset &lt; 0)</div><div class="line">	&#123;</div><div class="line">		throw new IllegalArgumentException(&quot;invalidate offset &quot; + offset);</div><div class="line">	&#125;</div><div class="line"></div><div class="line">	if (bytes.length - offset &lt; length)</div><div class="line">	&#123;</div><div class="line">		throw new IllegalArgumentException(&quot;invalidate length &quot; + bytes.length);</div><div class="line">	&#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>websocket协议的服务器的处理流程大致是上面这个流程，但是代码我只贴了关键部分，完整的代码可以去我的码云上下载。</p>
<h2 id="四-javascript客户端编写"><a href="#四-javascript客户端编写" class="headerlink" title="四.javascript客户端编写"></a>四.javascript客户端编写</h2><hr>
<figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;!DOCTYPE html&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">title</span>&gt;</span>Testing websockets<span class="tag">&lt;/<span class="name">title</span>&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">"Content-Type"</span> <span class="attr">content</span>=<span class="string">"text/html; charset=UTF-8"</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">div</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"submit"</span> <span class="attr">value</span>=<span class="string">"Start"</span> <span class="attr">onclick</span>=<span class="string">"start()"</span> /&gt;</span></div><div class="line">  <span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"messages"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span>&gt;</span><span class="javascript"></span></div><div class="line">    <span class="keyword">var</span> webSocket = </div><div class="line">      <span class="keyword">new</span> WebSocket(<span class="string">'ws://localhost:5678'</span>);</div><div class="line"></div><div class="line">    webSocket.onerror = <span class="function"><span class="keyword">function</span>(<span class="params">event</span>) </span>&#123;</div><div class="line">      onError(event)</div><div class="line">    &#125;;</div><div class="line"></div><div class="line">    webSocket.onopen = <span class="function"><span class="keyword">function</span>(<span class="params">event</span>) </span>&#123;</div><div class="line">      onOpen(event)</div><div class="line">    &#125;;</div><div class="line"></div><div class="line">    webSocket.onmessage = <span class="function"><span class="keyword">function</span>(<span class="params">event</span>) </span>&#123;</div><div class="line">      onMessage(event)</div><div class="line">    &#125;;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">function</span> <span class="title">onMessage</span>(<span class="params">event</span>) </span>&#123;</div><div class="line">		<span class="keyword">var</span> blob = event.data;</div><div class="line">		<span class="keyword">var</span> reader = <span class="keyword">new</span> FileReader();</div><div class="line">		reader.readAsText(blob, <span class="string">'utf-8'</span>);</div><div class="line">		reader.onload = <span class="function"><span class="keyword">function</span> (<span class="params">e</span>) </span>&#123;</div><div class="line">			<span class="built_in">document</span>.getElementById(<span class="string">'messages'</span>).innerHTML </div><div class="line">			+= <span class="string">'&lt;br /&gt;'</span> + reader.result;</div><div class="line">		&#125;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">function</span> <span class="title">onOpen</span>(<span class="params">event</span>) </span>&#123;</div><div class="line">      <span class="built_in">document</span>.getElementById(<span class="string">'messages'</span>).innerHTML </div><div class="line">        = <span class="string">'Connection established'</span>;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">function</span> <span class="title">onError</span>(<span class="params">event</span>) </span>&#123;</div><div class="line">      alert(event.data);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params"></span>) </span>&#123;</div><div class="line">      webSocket.send(<span class="string">'hellohellohellohellohellohellohellohellohe'</span>);</div><div class="line">    &#125;</div><div class="line">  <span class="tag">&lt;/<span class="name">script</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></div></pre></td></tr></table></figure>
<p>最好是下载程序下来，打上断点，debug去跟一下，每一步包做了那些处理，变成了什么样子，传输的二进制数据转换成字符串是甚么样子等等。</p>
<p>·······················································································································································</p>
<p>个人博客：<a href="http://z77z.oschina.io/">http://z77z.oschina.io/</a></p>
<p>此项目下载地址：<a href="https://git.oschina.net/z77z/springboot_mybatisplus" target="_blank" rel="external">https://git.oschina.net/z77z/springboot_mybatisplus</a></p>
<p>·······················································································································································</p>

        </div>

        <blockquote class="post-copyright">
    <div class="content">
        
<span class="post-time">
    最后更新时间：<time datetime="2017-06-07T13:42:41.348Z" itemprop="dateUpdated">2017-06-07 21:42:41</time>
</span><br>


        
    </div>
    <footer>
        <a href="http://z77z.oschina.io">
            <img src="/img/avatar.jpg" alt="邹海清">
            邹海清
        </a>
    </footer>
</blockquote>

        
<div class="page-reward">
    <a id="rewardBtn" href="javascript:;" class="page-reward-btn waves-effect waves-circle waves-light">赏</a>
</div>



        <div class="post-footer">
            
	<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/websocket/">websocket</a></li></ul>


            
<div class="page-share-wrap">
    

<div class="page-share" id="pageShare">
    <ul class="reset share-icons">
      <li>
        <a class="weibo share-sns" target="_blank" href="http://service.weibo.com/share/share.php?url=http://z77z.oschina.io/2017/06/05/即时通讯框架T-io之WebSocket协议再之HelloWorld/&title=《即时通讯框架T-io之WebSocket协议再之HelloWorld》 — z77z的小码窝&pic=http://z77z.oschina.io/img/avatar.jpg" data-title="微博">
          <i class="icon icon-weibo"></i>
        </a>
      </li>
      <li>
        <a class="weixin share-sns wxFab" href="javascript:;" data-title="微信">
          <i class="icon icon-weixin"></i>
        </a>
      </li>
      <li>
        <a class="qq share-sns" target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=http://z77z.oschina.io/2017/06/05/即时通讯框架T-io之WebSocket协议再之HelloWorld/&title=《即时通讯框架T-io之WebSocket协议再之HelloWorld》 — z77z的小码窝&source=" data-title=" QQ">
          <i class="icon icon-qq"></i>
        </a>
      </li>
      <li>
        <a class="facebook share-sns" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=http://z77z.oschina.io/2017/06/05/即时通讯框架T-io之WebSocket协议再之HelloWorld/" data-title=" Facebook">
          <i class="icon icon-facebook"></i>
        </a>
      </li>
      <li>
        <a class="twitter share-sns" target="_blank" href="https://twitter.com/intent/tweet?text=《即时通讯框架T-io之WebSocket协议再之HelloWorld》 — z77z的小码窝&url=http://z77z.oschina.io/2017/06/05/即时通讯框架T-io之WebSocket协议再之HelloWorld/&via=http://z77z.oschina.io" data-title=" Twitter">
          <i class="icon icon-twitter"></i>
        </a>
      </li>
      <li>
        <a class="google share-sns" target="_blank" href="https://plus.google.com/share?url=http://z77z.oschina.io/2017/06/05/即时通讯框架T-io之WebSocket协议再之HelloWorld/" data-title=" Google+">
          <i class="icon icon-google-plus"></i>
        </a>
      </li>
    </ul>
 </div>



    <a href="javascript:;" id="shareFab" class="page-share-fab waves-effect waves-circle">
        <i class="icon icon-share-alt icon-lg"></i>
    </a>
</div>



        </div>
    </div>

    
<nav class="post-nav flex-row flex-justify-between flex-row-reverse">
  

  
    <div class="waves-block waves-effect next">
      <a href="/2017/04/23/SpringBoot-Mybatis_Plus学习记录之公共字段自动填充/" id="post-next" class="post-nav-link">
        <div class="tips">Next <i class="icon icon-angle-right icon-lg icon-pl"></i></div>
        <h4 class="title">SpringBoot-Mybatis_Plus学习记录之公共字段自动填充</h4>
      </a>
    </div>
  
</nav>



    










    <div id="cloud-tie-wrapper" class="comments cloud-tie-wrapper"></div>
    <script>
    var cloudTieConfig = {
        url: 'http://z77z.oschina.io/2017/06/05/即时通讯框架T-io之WebSocket协议再之HelloWorld/index.html',
        sourceId: '即时通讯框架T-io之WebSocket协议再之HelloWorld',
        productKey: '64500aaa7f0a4f6f804c4df9b5880011',
        target: 'cloud-tie-wrapper',
        pcFiles: [
            '/css/cloudTie/pc.css?v=1.4.3',
            '/js/cloudTie/pc.min.js?v=1.4.3',
        ],
        mobileFiles: [
            '/css/cloudTie/mobile.css?v=1.4.3',
            '/js/cloudTie/mobile.min.js?v=1.4.3'
        ]
    };
    </script>
    <script src="/js/cloudTie/loader.min.js?v=1.4.3"></script>







</article>

<div id="reward" class="page-modal reward-lay">
    <a class="close" href="javascript:;"><i class="icon icon-close"></i></a>
    <h3 class="reward-title">
        <i class="icon icon-quote-left"></i>
        我只要一角钱~ ~
        <i class="icon icon-quote-right"></i>
    </h3>
    <ul class="reward-items">
        
        <li>
            <img src="/img/wechat.png" title="微信打赏二维码" alt="微信打赏二维码">
            <p>微信</p>
        </li>
        

        
        <li>
            <img src="/img/alipay.jpg" title="支付宝打赏二维码" alt="支付宝打赏二维码">
            <p>支付宝</p>
        </li>
        
    </ul>
</div>



</div>

        <footer class="footer">
    <div class="top">
        
<p>
    <span id="busuanzi_container_site_uv" style='display:none'>
        站点总访客数：<span id="busuanzi_value_site_uv"></span>
    </span>
    <span id="busuanzi_container_site_pv" style='display:none'>
        站点总访问量：<span id="busuanzi_value_site_pv"></span>
    </span>
</p>


        <p>
            
                <span><a href="/atom.xml" target="_blank" class="rss" title="rss"><i class="icon icon-lg icon-rss"></i></a></span>
            
            <span>博客内容遵循<a rel="license" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">知识共享 署名 - 非商业性 - 相同方式共享 4.0 国际协议</a></span>
        </p>
    </div>
    <div class="bottom">
        <p>
            <span>Power by <a href="http://hexo.io/" target="_blank">Hexo</a> Theme <a href="https://github.com/yscoder/hexo-theme-indigo" target="_blank">indigo</a></span>
            <span>邹海清 &copy; 2016 - 2017</span>
        </p>
    </div>
</footer>

    </main>
    <div class="mask" id="mask"></div>
<a href="javascript:;" id="gotop" class="waves-effect waves-circle waves-light"><span class="icon icon-lg icon-chevron-up"></span></a>



<div class="global-share" id="globalShare">
    <ul class="reset share-icons">
      <li>
        <a class="weibo share-sns" target="_blank" href="http://service.weibo.com/share/share.php?url=http://z77z.oschina.io/2017/06/05/即时通讯框架T-io之WebSocket协议再之HelloWorld/&title=《即时通讯框架T-io之WebSocket协议再之HelloWorld》 — z77z的小码窝&pic=http://z77z.oschina.io/img/avatar.jpg" data-title="微博">
          <i class="icon icon-weibo"></i>
        </a>
      </li>
      <li>
        <a class="weixin share-sns wxFab" href="javascript:;" data-title="微信">
          <i class="icon icon-weixin"></i>
        </a>
      </li>
      <li>
        <a class="qq share-sns" target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=http://z77z.oschina.io/2017/06/05/即时通讯框架T-io之WebSocket协议再之HelloWorld/&title=《即时通讯框架T-io之WebSocket协议再之HelloWorld》 — z77z的小码窝&source=" data-title=" QQ">
          <i class="icon icon-qq"></i>
        </a>
      </li>
      <li>
        <a class="facebook share-sns" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=http://z77z.oschina.io/2017/06/05/即时通讯框架T-io之WebSocket协议再之HelloWorld/" data-title=" Facebook">
          <i class="icon icon-facebook"></i>
        </a>
      </li>
      <li>
        <a class="twitter share-sns" target="_blank" href="https://twitter.com/intent/tweet?text=《即时通讯框架T-io之WebSocket协议再之HelloWorld》 — z77z的小码窝&url=http://z77z.oschina.io/2017/06/05/即时通讯框架T-io之WebSocket协议再之HelloWorld/&via=http://z77z.oschina.io" data-title=" Twitter">
          <i class="icon icon-twitter"></i>
        </a>
      </li>
      <li>
        <a class="google share-sns" target="_blank" href="https://plus.google.com/share?url=http://z77z.oschina.io/2017/06/05/即时通讯框架T-io之WebSocket协议再之HelloWorld/" data-title=" Google+">
          <i class="icon icon-google-plus"></i>
        </a>
      </li>
    </ul>
 </div>


<div class="page-modal wx-share" id="wxShare">
    <a class="close" href="javascript:;"><i class="icon icon-close"></i></a>
    <p>扫一扫，分享到微信</p>
    <img src="" alt="微信分享二维码">
</div>




    <script src="//cdn.bootcss.com/node-waves/0.7.4/waves.min.js"></script>
<script>
var BLOG = { ROOT: '/', SHARE: true, REWARD: true };



lazyScripts.push('//s95.cnzz.com/z_stat.php?id=1261081671&web_id=1261081671')

</script>

<script src="/js/main.min.js?v=1.4.3"></script>


<div class="search-panel" id="search-panel">
    <ul class="search-result" id="search-result"></ul>
</div>
<template id="search-tpl">
<li class="item">
    <a href="{path}" class="waves-block waves-effect">
        <div class="title ellipsis" title="{title}">{title}</div>
        <div class="flex-row flex-middle">
            <div class="tags ellipsis">
                {tags}
            </div>
            <time class="flex-col time">{date}</time>
        </div>
    </a>
</li>
</template>

<script src="/js/search.min.js?v=1.4.3" async></script>






<script async src="//dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>



<script>
(function() {
    var OriginTitile = document.title, titleTime;
    document.addEventListener('visibilitychange', function() {
        if (document.hidden) {
            document.title = '死鬼去哪里了！';
            clearTimeout(titleTime);
        } else {
            document.title = '(つェ⊂)咦!又好了!';
            titleTime = setTimeout(function() {
                document.title = OriginTitile;
            },2000);
        }
    });
})();
</script>



</body>
</html>
